#!/bin/bash

set -u
set -e

#################### Lib #######################
red=$(tput setaf 1)
green=$(tput setaf 2)
yellow=$(tput setaf 3)
blue=$(tput setaf 4)
purple=$(tput setaf 5)
cyan=$(tput setaf 6)
reset=$(tput sgr0)
error() {
    echo "$red[ ERROR ]$reset $1" >&2
}
warn() {
    echo "$yellow[ WARN ]$reset $1"
}
info() {
    echo "$green[ INFO ]$reset $1"
}
all_exist() {
    for i in "$@"; do
        if [ ! -e "$i" ]; then
            # error "$i 不存在"
            return 1
        fi
    done
    return 0
}

all_not_exist() {
    for i in "$@"; do
        if [ -e "$i" ]; then
            return 1
        fi
    done
    return 0
}

need() {
    if ! hash "$1" &>/dev/null; then
        error "$1 not found !"
        return 1
    fi
    return 0
}
####### Check ENV #########
check_env() {
    all_exist ./ovpn.ini || {
        error "ovpn.ini 不存在"
        exit 1
    }
    need make-cadir && need openvpn && need curl && need route || {
        info "请安装依赖: net-tools curl easy-rsa openvpn libssl-dev openssl"
        exit 1
    }
}
####### Generate Server #########
_generate_server() {
    make-cadir $HOME/.certs
    cd $HOME/.certs

    echo "set_var EASYRSA_REQ_COUNTRY \"$EASYRSA_REQ_COUNTRY\"" >>vars
    echo "set_var EASYRSA_REQ_PROVINCE \"$EASYRSA_REQ_PROVINCE\"" >>vars
    echo "set_var EASYRSA_REQ_CITY \"$EASYRSA_REQ_CITY\"" >>vars
    echo "set_var EASYRSA_REQ_ORG \"$EASYRSA_REQ_ORG\"" >>vars
    echo "set_var EASYRSA_REQ_EMAIL \"$EASYRSA_REQ_EMAIL\"" >>vars
    echo "set_var EASYRSA_REQ_OU \"$EASYRSA_REQ_OU\"" >>vars

    ./easyrsa init-pki
    info "[✔] PKI目录"
    ./easyrsa build-ca nopass
    info "[✔] CA证书"
    ./easyrsa gen-req server nopass
    info "[✔] server证书"
    echo 'yes' | ./easyrsa sign server server
    info "[✔] server证书签名"
    ./easyrsa gen-dh
    info "[✔] Diffie-Hellman密钥交换"
    ./easyrsa gen-crl
    info "[✔]  crl.pem 吊销证书"

    cat >/etc/openvpn/server/server.conf <<-EOF
        port $port
        proto tcp
        dev tun
        cert /etc/openvpn/certs/pki/issued/server.crt
        key /etc/openvpn/certs/pki/private/server.key
        dh /etc/openvpn/certs/pki/dh.pem
        ca /etc/openvpn/certs/pki/ca.crt
        crl-verify /etc/openvpn/certs/pki/crl.pem
        server $net $mask
        push "route $(route -n | awk '{if(NR==4)print $1,$3;}')"
        ifconfig-pool-persist ipp.txt
        status openvpn-status.log
        log /var/log/openvpn/openvpn.log
        keepalive 10 120
        max-clients 100
        verb 3
        client-to-client
        persist-key
        persist-tun
        duplicate-cn
EOF
    info "[✔]  server.conf 配置文件"
    ln -sf $HOME/.certs /etc/openvpn/certs
    info "[✔]  链接成功"
    cat >/lib/systemd/system/SimpleOpenVPN.service <<-EOF
        [Unit]
        Description=SimpleOpenVPN Server Service
        After=network.target

        [Service]
        Type=simple
        User=$(whoami)
        Restart=on-failure
        RestartSec=5s
        ExecStart=/sbin/openvpn --config /etc/openvpn/server/server.conf 
        LimitNOFILE=1048576

        [Install]
        WantedBy=multi-user.target
EOF
    info "[✔]  SimpleOpenVPN服务添加成功"
    echo "请通过 systemctl -f enable SimpleOpenVPN 命令添加到开机自启"
    echo "或通过 systemctl start SimpleOpenVPN 命令临时启动"
}
generate_server() {
    all_not_exist $HOME/.certs && _generate_server || {
        error "$HOME/.certs已经存在"
        exit 1
    }
}
####### Generate Client #########
_add_client() {
    ./easyrsa gen-req $client nopass
    info "[✔]  $client 证书"
    echo 'yes' | ./easyrsa sign client $client
    info "[✔]  $client 签名成功"
    cat >./$client.ovpn <<-EOF
        client
        dev tun
        proto tcp
        remote $(curl ifconfig.me) $port
        resolv-retry infinite
        nobind
        ca ca.crt
        cert $client.crt
        key $client.key
        verb 3
        persist-key
        persist-tun
        remote-cert-tls server
        auth-nocache
EOF
    info "[✔]  $client 配置文件"
    tar -czf "$client.tar.gz" \
        ./pki/ca.crt \
        ./pki/private/$client.key \
        ./pki/issued/$client.crt \
        ./$client.ovpn --transform 's#^./pki/private#.#;s#^./pki/issued#.#;s#^./pki#.#;'
    ./easyrsa gen-crl
    info "[✔] 更新 crl.pem"
    mv $client.tar.gz /etc/openvpn/client
    info "[✔]  打包至/etc/openvpn/client"
}
add_client() {
    cd $HOME/.certs
    read -p "请输入添加的客户端名称$yellow?$reset " client
    if [ "$client" = "server" -o "$client" = "" ]; then
        error "非法的名称"
        exit 1
    fi
    all_not_exist ./pki/private/$client.key \
        ./pki/issued/$client.crt \
        ./$client.ovpn \
        /etc/openvpn/client/$client.tar.gz &&
        _add_client || warn "$client 相关文件已经存在"
}
####### Remove Client #########
remove_client() {
    cd $HOME/.certs
    choices=$(cat ./pki/index.txt | grep -P '^V.*(?<!server)$' | cut -d = -f2)
    if [ -z "$choices" ];then
        warn "没有有效的客户端,请先添加客户端"
        exit 0
    fi
    PS3="请输入删除的客户端名称$yellow?$reset"
    select client in $choices; do
        echo "Choose  $green$client$reset"
        break
    done

    ./easyrsa revoke "$client"
    info "[✔] 吊销 $client"
    ./easyrsa gen-crl
    info "[✔] 更新 crl.pem"
    rm -f ./pki/private/$client.key \
        ./pki/issued/$client.crt \
        ./$client.ovpn \
        /etc/openvpn/client/$client.tar.gz
    info "[✔] 清理文件"
}
################### Main ########################
check_env
eval "$(cat ./ovpn.ini | sed 's/;.*$//g' | grep '=')"
PS3="$green请选择操作$reset ? "
select choice in Generate-server Add-client Remove-client List-index; do
    echo "You choose No.$REPLY,$choice"
    case "$REPLY" in
    1) generate_server ;;
    2) add_client ;;
    3) remove_client ;;
    4)
        cd $HOME/.certs
        cat ./pki/index.txt | grep 'V'
        ;;
    esac
    break
done
